/*
 * Tools.c
 *
 *  Created on: 26.05.2011
 *      Author: sili
 */

#include "Tools.h"

static long globalId = 0;

void Tools::getStringAttributeValue(DOMNode * _node, const char * _searchKey, string * _buffer){
	_buffer->clear();
	XMLCh * searchKey = XMLString::transcode(_searchKey);
	if(_node->getAttributes() != NULL){
		DOMNode * nodeAttribute = _node->getAttributes()->getNamedItem(searchKey);
		if(nodeAttribute != NULL){
			char * value = XMLString::transcode(nodeAttribute->getNodeValue());
			_buffer->append(value);
			XMLString::release(&value);
		} else {
			DOMNamedNodeMap * attributes = _node->getAttributes();
			for( XMLSize_t yy = 0; yy < attributes->getLength(); ++yy ){
				//printf("  %s=%s \n", XMLString::transcode(attributes->item(yy)->getNodeName()), XMLString::transcode(attributes->item(yy)->getNodeValue()));
			}
		}
	}
	XMLString::release(&searchKey);
}

int Tools::getIntAttributeValue(DOMNode * _node, const char * _searchKey){
	string buffer = "";
	getStringAttributeValue(_node,_searchKey, & buffer);
	int value = -1;
	try {
		value = Tools::getIntFromString(buffer.c_str());
	} catch(const int toCatch) {
		printf("Can't convert string:%s to integer for the _searchKey %s! \n", buffer.c_str(), _searchKey);
	}
	return value;
}

double Tools::getDoubleAttributeValue(DOMNode * _node, const char * _searchKey){
	string buffer = "";
	getStringAttributeValue(_node,_searchKey, & buffer);
	double value = -1.0;
	try {
		value = Tools::getDoubleFromString(buffer.c_str());
	} catch(const int toCatch) {
		printf("Can't convert string:%s to double! \n", buffer.c_str());
	}
	return value;
}

long Tools::getNewGlobalId(){
	return ++globalId;
}

void Tools::stringCopy(char * dst, const char * src, size_t len) {
	strncpy(dst, src, len);
	dst[len - 1] = '\0';
}


void Tools::createSvgTemplateFile(DOMDocument * _doc, DOMNode * _node, const char * _templateFile, int _width, int _height){
	printf("      [Tools.createSvgTemplateFile] file:%s \n", _templateFile);

	const int length = 100;
	char integerBuffer[length];
	XMLCh tempStr0[length];
	XMLCh tempStr1[length];

	XMLString::transcode("LS", tempStr0, length-1);
	DOMImplementation * svgImpl = DOMImplementationRegistry::getDOMImplementation(tempStr0);
	XMLString::transcode("svg", tempStr0, length-1);
	DOMDocument * svgDoc = svgImpl->createDocument(0, tempStr0, 0);
	DOMElement * svgRoot = svgDoc->getDocumentElement();

	XMLString::transcode("defs", tempStr0, length-1);
	DOMNodeList * defsList = _doc->getElementsByTagName(tempStr0);

	// TODO reduce defs. (use only this which are needed in this aalItem)
	for( XMLSize_t defIndex = 0; defIndex < defsList->getLength(); ++defIndex ){
		DOMNode * svgDef = defsList->item(defIndex);
		DOMNode * svgDefClone = svgDoc->importNode(svgDef,true);
		svgRoot->appendChild(svgDefClone);
	}

	DOMElement * svgContentClone = (DOMElement*)svgDoc->importNode(_node,true);

	snprintf(integerBuffer, (size_t)length-1, "%d", _width);
	XMLString::transcode("width", tempStr0, length-1);
	XMLString::transcode(integerBuffer, tempStr1, length-1);
	svgRoot->setAttribute(tempStr0,tempStr1);

	snprintf(integerBuffer, (size_t)length-1, "%d", _height);
	XMLString::transcode("height", tempStr0, length-1);
	XMLString::transcode(integerBuffer, tempStr1, length-1);
	svgRoot->setAttribute(tempStr0,tempStr1);

	// delete the transorm attribute cause this will be now a template with full size
	XMLString::transcode("transform", tempStr0, length-1);
	svgContentClone->removeAttribute(tempStr0);

	svgRoot->appendChild(svgContentClone);

	createXmlFileFromDOMDocument(_templateFile,svgDoc);
	svgDoc->release();
}

void Tools::createXmlFileFromDOMDocument(const char * _filename, DOMDocument * _doc) {
	//printf("    [Tools::createXmlFileFromDOMDocument] filename: %s\n", _filename);

	// delete file if exists.
	if(remove(_filename) != 0){
		// printf("      [Tools.createXmlFileFromDOMDocument] can't remove file or the file doesn't exists.\n");
	}

	// printf("      [Tools.createXmlFileFromDOMDocument] creating new file %s \n", _filename);
	DOMWriter * writer = ((DOMImplementationLS*)_doc->getImplementation())->createDOMWriter();
	// set the format-pretty-print feature
	if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
		writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
	// set the byte-order-mark feature
	if (writer->canSetFeature(XMLUni::fgDOMWRTBOM, true))
		writer->setFeature(XMLUni::fgDOMWRTBOM, true);
	XMLFormatTarget * target = new LocalFileFormatTarget(_filename);

	writer->writeNode(target, * _doc);
	target->flush();

	writer->release();
	delete(target);
}

DOMDocument * Tools::createDOMFromXmlFile(const char * _xmlFilename, XercesDOMParser * _parser){
	_parser->setValidationScheme(XercesDOMParser::Val_Always);
	_parser->setDoNamespaces(true);								//optional

	ErrorHandler * errHandler = (ErrorHandler*) new HandlerBase();
	_parser->setErrorHandler(errHandler);

	try {
		_parser->parse(_xmlFilename);
	} catch (const XMLException& toCatch) {
		char* message = XMLString::transcode(toCatch.getMessage());
		printf("  [Tools::createDOMFromXmlFile] Exception while parsing %s. Error message is: %s\n", _xmlFilename, message);
		XMLString::release(&message);
		return NULL;
	} catch (const DOMException& toCatch) {
		char* message = XMLString::transcode(toCatch.msg);
		printf("  [Tools::createDOMFromXmlFile] Exception while parsing %s. Error message is: %s\n", _xmlFilename, message);
		XMLString::release(&message);
		return NULL;
	}catch (...) {
		printf("  [Tools::createDOMFromXmlFile] Exception while parsing %s. Unexpected Exception.\n", _xmlFilename);
		return NULL;
	}
	return _parser->getDocument();
}

bool Tools::renameFile(const char * _oldFileName, const char * _newFileName, string * _response){
	char resBuff[500];
	int renameResult = 0;

	// check if the _oldFileName file exists
	char * oldPath = canonicalize_file_name(_oldFileName);
	if(!oldPath){
		sprintf(resBuff,"Can't rename %s to %s because can't find the old file.", _oldFileName, _newFileName);
		_response->clear();
		_response->append(resBuff);
		return false;
	} else {
		// oldPath file exists, we may rename it to newPath
		// check if newPath doesn't exists
		char * newPath = canonicalize_file_name(_newFileName);
		if(newPath){
			sprintf(resBuff,"Can't rename %s to %s because new file already exists.", _oldFileName, _newFileName);
			_response->clear();
			_response->append(resBuff);
			return false;
		} else {
			// everything ok, rename now
			renameResult = rename(_oldFileName, _newFileName);
		}
		delete(newPath);
	}
	delete(oldPath);
	return renameResult == 0;
}

int Tools::getIntFromString(const char * _string) throw(int){
	errno = 0;
	char * end_ptr;
	long long_var = strtol(_string,&end_ptr, 10);
	if (ERANGE == errno){
		throw 0;
	} else if (long_var > INT_MAX) {
		throw 0;
	} else if (long_var < INT_MIN) {
		throw 0;
	} else if (end_ptr == _string) {
		throw 0;
	}
	return (int)long_var;
}

double Tools::getDoubleFromString(const char * _string) throw(int){
	errno = 0;
	char * end_ptr;
	double double_var = strtod(_string,&end_ptr);

	if (ERANGE == errno){
		throw 0;
	} else if (end_ptr == _string) {
		throw 0;
	}
	return double_var;
}

void Tools::execCmd(char * cmd, string * cmdResult) {
	cmdResult->clear();
	FILE* pipe = popen(cmd, "r");
	if (!pipe){
		return;
	}
	char buffer[128];
	while(!feof(pipe)) {
		if(fgets(buffer, 128, pipe) != NULL)
			cmdResult->append(buffer);
	}
	pclose(pipe);
}

void Tools::split(const char * _input, const char * _delim, vector<string> * _buffer){
	_buffer->clear();
	char * token = strtok((char*)_input,_delim);
	if(token == NULL){
		_buffer->push_back(_input);
		return;
	}
	while(token != NULL){
		_buffer->push_back(token);
		token = strtok(NULL,_delim);
	}
}

bool Tools::endsWith(const string & a, const string & b) {
	if (b.size() > a.size()) return false;
	return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
}
